<?php

require_once 'components/utils/string_utils.php';

interface IConditionImp
{
    function PutExpressionInBrackets(IExpression $expr);
}

class GenericConditionImp implements IConditionImp
{
    public function PutExpressionInBrackets(IExpression $expr)
    {
        return '(' . $expr->AsSql($this) . ')';
    }
}

interface IExpression
{
    /**
     * @abstract
     * @param IConditionImp $imp
     * @return string
     */
    function AsSql(IConditionImp $imp);
}

class Literal
{
    public static function String($value)
    {
        return new StringLiteral($value);
    }

    public static function Number($value)
    {
        return new NumberLiteral($value);
    }

    public static function Boolean($value)
    {
        return new BooleanLiteral($value);
    }
}

class NumberLiteral implements IExpression
{
    private $value;

    public function __construct($value)
    {
        $this->value = $value;
    }

    /**
     * @param IConditionImp $imp
     * @return string
     */
    function AsSql(IConditionImp $imp)
    {
        return $this->value;
    }
}

class BooleanLiteral implements IExpression
{
    private $value;

    public function __construct($value)
    {
        $this->value = $value;
    }

    /**
     * @param IConditionImp $imp
     * @return string
     */
    function AsSql(IConditionImp $imp)
    {
        return $this->value ? 'TRUE' : 'FALSE';
    }
}

class StringLiteral implements IExpression
{
    private $value;

    public function __construct($value)
    {
        $this->value = $value;
    }

    /**
     * @param IConditionImp $imp
     * @return string
     */
    function AsSql(IConditionImp $imp)
    {
        return '\'' . $this->value . '\'';
    }
}


class FieldName implements IExpression
{
    public static function Short($fieldName)
    {
        return new FieldName($fieldName);
    }

    public static function Full($parentName, $fieldName)
    {
        return new FieldName($fieldName, $parentName);
    }

    private $fieldName;
    private $parentName;

    public function __construct($fieldName, $parentName = null)
    {
        $this->fieldName = $fieldName;
        $this->parentName = $parentName;
    }

    /**
     * @param IConditionImp $imp
     * @return string
     */
    function AsSql(IConditionImp $imp)
    {
        if ($this->parentName == null)
            return $this->fieldName;
        else
            return $this->parentName . '.' . $this->fieldName;
    }
}

class BinaryOperator
{
    public static $Equals;

    public final static function Init()
    {
        self::$Equals = new BinaryOperator();
    }
}
BinaryOperator::Init();

class BinaryCondition implements IExpression
{
    private $left;
    private $operator;
    private $right;

    public function __construct(IExpression $left, BinaryOperator $operator, IExpression $right)
    {
        $this->left = $left;
        $this->operator = $operator;
        $this->right = $right;
    }

    /**
     * @param IConditionImp $imp
     * @return string
     */
    public final function AsSql(IConditionImp $imp)
    {
        return $this->left->AsSql($imp) . ' = ' . $this->right->AsSql($imp);
    }
}

class UnaryOperator
{
    public static $Not;

    public static function Init()
    {
        self::$Not = new UnaryOperator();
    }

    public function __construct()
    {
        
    }
}
UnaryOperator::Init();
        
class UnaryCondition implements IExpression
{
    private $expression;
    private $operator;

    public function __construct(UnaryOperator $operator, IExpression $expression)
    {
        $this->expression = $expression;
        $this->operator = $operator;
    }

    /**
     * @param IConditionImp $imp
     * @return string
     */
    function AsSql(IConditionImp $imp)
    {
        return 'NOT ' . $this->expression->AsSql($imp);
    }
}

class MultiOperator
{
    public static $And;

    public static function Init()
    {
        self::$And = new MultiOperator();
    }

    public function __construct()
    {

    }
}
MultiOperator::Init();

class MultiCondition implements IExpression
{
    private $operator;
    private $arguments;

    /**
     * @param MultiOperator $operator
     * @param IExpression[] $arguments
     */
    public function __construct(MultiOperator $operator, $arguments)
    {
        $this->operator = $operator;
        $this->arguments = $arguments;
    }

    public function Add(IExpression $argument)
    {
        $this->arguments[] = $argument;
    }

    /**
     * @param IConditionImp $imp
     * @return string
     */
    function AsSql(IConditionImp $imp)
    {
        $result = '';
        foreach($this->arguments as $argument)
        {
            StringUtils::AddStr($result, $imp->PutExpressionInBrackets($argument), ' AND ');
        }
        return $result;
    }
}

?>